package table;

import java.util.Random;

import log.Logger;
import log.NullLogger;
import log.SimpleLogger;

import philosoph.*;
import user.util.GenericArray;

public class RoundWalkingTable <T extends Philosoph> implements ITable<T> {

	private GenericArray<T> seats;
	private Object[] sync;
//	private Object waitSync = new Object();
	private Logger logger = new NullLogger();

	public RoundWalkingTable(int seats) {
		this(seats, new SimpleLogger());
	}

	public RoundWalkingTable(int seats, Logger logger) {
		this.logger = logger;
		if (seats < 2) throw new IllegalArgumentException();
		this.seats = new GenericArray<T>(seats >> 1);
		this.sync = new Object[seats >> 1];
		for (int i = 0; i < sync.length; i++) {
			sync[i] = new Object();
		}
	}

	public boolean sitNEat(final T philosoph) throws InterruptedException {
		return this.sitNEat(philosoph, new Random().nextInt(this.sync.length));
	}

	public boolean sitNEat(final T philosoph, final int seat) throws InterruptedException {
		String name = philosoph.getName();
		
		int seatNumber = this.getSeat(philosoph, seat);
		if(seatNumber < 0) {
			this.logger.log("Table:\t\t " + name + " found no seat on this table.");
			return false;
		}
		this.logger.log("Table:\t\t " + name + " starts eating on seat " + String.format("%4d", seatNumber << 1) + ".");
		philosoph.eat();
		this.release(seatNumber);
		this.logger.log("Table:\t\t " + name + " finished eating, releases seat " + String.format("%4d", seatNumber << 1) + ".");
		return true;
	}

	private void release(int seatNumber) {
		synchronized (this.sync[seatNumber]) {
			this.seats.set(seatNumber, null);
		}
	}
	
	private int getSeat(T philosoph, int seat) throws InterruptedException {
		for (int i = 0, j = seat; i < this.sync.length ; i++, j++) {
			if (j >= this.sync.length) j = 0;
			synchronized (this.sync[j]) {
				if (this.seats.get(j) == null) {
					this.seats.set(j, philosoph);
					return j;
				}
			}
		}
		return -1;
	}

}
